#ifndef _M_TCP_H_
#define _M_TCP_H_

#define MAX_LISTEN 1024

#include<arpa/inet.h>
#include<cstdio>
#include<unistd.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<iostream>
#include<string>
using namespace std;

class TcpSocket
{
  private:
    int _socket;//套接字描述符
  public:
    TcpSocket()
      :_socket(-1) 
    {}
    ~TcpSocket()
    {
        Close();
    }
    bool Socket()//创建套接字
    {
        _socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(_socket<0)
        {
            cout<<"socket error!!"<<endl;
            return false;
        }
        return true;
    }
    bool Bind(const string &ip,uint16_t port)//绑定套接字到指定的IP和端口
    {
        struct sockaddr_in addr;
        addr.sin_family=AF_INET;
        addr.sin_port=htons(port);//将端口转换为网络字节序
        addr.sin_addr.s_addr=inet_addr(ip.c_str());//将IP地址转换为网络字节序

        socklen_t addrlen=sizeof(struct sockaddr_in);
        int ret=bind(_socket,(struct sockaddr*)&addr,addrlen);//绑定套接字到指定的IP和端口
        if(ret<0)
        {
            cout<<"bind error!!!"<<endl;
            return false;
        }
        return true;
    }
    bool Listen(int backlog=MAX_LISTEN)//监听套接字
    {
        int ret=listen(_socket,backlog);//开始监听连接请求
        if(ret<0)
        {
            cout<<"listen error!!!"<<endl;
            return false;
        }
        return true;
    }
    bool Accept(TcpSocket *sock,string *cli_ip,uint16_t *cli_port)//接受新的连接请求，返回新的套接字描述符
    {
        struct sockaddr_in peer;
        socklen_t addrlen=sizeof(struct sockaddr_in);
        int newfd=accept(_socket,(struct sockaddr*)&peer,&addrlen);//接受新连接请求并返回新的套接字描述符
        if(newfd<0)
        {
            cout<<"accpet error!!!"<<endl;
            return false;
        }
        sock->_socket=newfd;//将新的套接字描述符赋值给传入的TcpSocket对象
        if(cli_ip!=nullptr)
        {
            *cli_ip=inet_ntoa(peer.sin_addr);//获取客户端IP地址，并转换为点分十进制字符串
        }
        if(cli_port!=nullptr)
        {
            *cli_port=ntohs(peer.sin_port);//将客户端端口从网络字节序转换为主机字节序
        }
        return true;
    }
    bool Recv(string* body)//接收信息
    {
        char tmp[1024]={0};
        ssize_t ret=recv(_socket,tmp,1024,0);//接收数据，ret显示为接收到的字节数，0代表默认阻塞接收
        if(ret<0)
        {
            cout<<"recv error!!!!"<<endl;
            return false;
        }
        else if(ret==0)//连接被对方关闭
        {
            cout<<"connect shutdown!!!"<<endl;
            return false;
        }
        body->assign(tmp,ret);//从tmp中截取ret大小的数据，并将接收到的数据赋值给传入的字符串对象body
        return true;
    }
    bool Send(const string& body)//发送信息
    {
        ssize_t ret=send(_socket,body.c_str(),body.size(),0);//发送数据，ret为发送的字节数，0代表默认阻塞发送
        if(ret<0)
        {
            cout<<"send error!!!"<<endl;
            return false;
        }
        return true;
    }
    bool Connect(const string& ip,int port)//连接到指定的IP和端口
    {
        struct sockaddr_in addr;
        addr.sin_family=AF_INET;
        addr.sin_port=htons(port);//将端口转为网络字节序
        addr.sin_addr.s_addr=inet_addr(ip.c_str());//将IP地址转换为网络字节序
        socklen_t len=sizeof(struct sockaddr_in);
        int ret=connect(_socket,(struct sockaddr*)&addr,len);
        if(ret<0)
        {
            cout<<"connect error!!!"<<endl;
            return false;
        }
        return true;
    }
    bool Close()//关闭套接字
    {
        if(_socket!=-1)//只要有连接，就关闭
        {
            close(_socket);
            _socket=-1;
        }
        return true;
    }
};

#endif